﻿using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.Metadata.Entity.DataModel
{
    [Serializable]
    public class StateMachineRefSchemaEntity : IRefSchemaEntity
    {
        public string ID { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public Dictionary<string, State> States { get; set; }
        public Dictionary<string, Event> Events { get; set; }

        [Serializable]
        public class State
        {
            public string Code { get; set; }
            public Dictionary<string, Rule> Rules { get; set; }

            public static State Mapping(StateMachineMetadata sm, TState state)
            {
                if (sm == null || state == null) return default;
                var stateObj = new State
                {
                    Code = $"{state.Key}",
                };
                if (state.Rules != null && state.Rules.Count > 0) 
                {
                    stateObj.Rules = new Dictionary<string, Rule>();
                    foreach (var rule in state.Rules)
                    {
                        stateObj.Rules[rule.ID.Replace("-", "")] = Rule.Mapping(sm, state, rule);
                    }
                }
                return stateObj;
            }
        }

        [Serializable]
        public class Rule
        {
            public string Code { get; set; }
            public string Key { get; set; }
            public string Name { get; set; }
            public string Text { get; set; }
            public bool IsPreCheck { get; set; }

            public static Rule Mapping(StateMachineMetadata sm, TState state, TRule rule)
            {
                if (sm == null || state == null || rule == null) return default;
                var ru = new Rule
                {
                    Code = rule.ID,
                    Key = rule.Key,
                    Name = rule.Name,
                    Text = string.IsNullOrEmpty(rule.Description) ? rule.Name : rule.Description,
                    IsPreCheck = rule.IsPreCheck,
                };
                return ru;
            }
        }

        [Serializable]
        public class Event
        {
            public string Code { get; set; }
            public string Text { get; set; }
            public string Description { get; set; }
            public int? From { get; set; }
            public int To { get; set; }
            public Dictionary<string, Action> Actions { get; set; }

            public static Event Mapping(StateMachineMetadata sm, TEvent even)
            {
                if (sm == null || even == null) return default;
                var trans = sm.Transitions.FirstOrDefault(t => t.EventID == even.ID);
                if (trans == null)
                    throw new Exception($"{sm.Code}元数据获取不到事件：{even.Key}所属的trans");
                int? fromKey = sm.States.FirstOrDefault(s => s.ID == trans.FromStateID)?.Key;
                int? toKey = sm.States.FirstOrDefault(s => s.ID == trans.ToStateID)?.Key;
                var eve = new Event
                {
                    Code = even.Key,
                    Text = even.Name, 
                    Description = even.Description,
                    From = fromKey,
                    To = toKey.Value,
                };
                if (trans.Actions != null && trans.Actions.Count > 0)
                {
                    eve.Actions = new Dictionary<string, Action>();
                    foreach (var act in trans.Actions)
                    {
                        eve.Actions[act.ID.Replace("-", "")] = Action.Mapping(sm, even, act);
                    }
                }
                return eve;
            }
        }

        [Serializable]
        public class Action
        {
            public string Code { get; set; }
            public string Text { get; set; }
            public string Target { get; set; }

            public static Action Mapping(StateMachineMetadata sm, TEvent even, TAction action)
            {
                if (sm == null || even == null || action == null) return default;
                var act = new Action
                {
                    Code = action.Key,
                    Text = action.Name,
                    Target = action.Target,
                };
                return act;
            }
        }
    }
}
